1 /* 2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021 3 License: [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License]. 4 Authors: Marcelo S. N. Mancini 5 6 Copyright Marcelo S. N. Mancini 2018 - 2021. 7 Distributed under the CC BY-4.0 License. 8 (See accompanying file LICENSE.txt or copy at 9 https://creativecommons.org/licenses/by/4.0/ 10 */ 11 module hip.api.data.tilemap; 12 public import hip.api.renderer.texture; 13 14 /** 15 * TileLayers representations which can be found from Tiled. 16 */ 17 enum TileLayerType 18 { 19 ///The Default one, a data structure holding tile mapping information. 20 TILE_LAYER = "tilelayer", 21 ///A simple layer, containing only an image to be rendered above or below the tile layers. 22 IMAGE_LAYER = "imagelayer", 23 ///A layer used only to hold data to be used within the gameplay implementation 24 OBJECT_LAYER = "objectgroup" 25 } 26 27 enum TileDrawOrder 28 { 29 TOP_DOWN, 30 DOWN_TOP 31 } 32 33 /** 34 * Simple Key/Value type defining a property inside a Tile. 35 */ 36 struct TileProperty 37 { 38 string name; 39 string type; 40 string value; 41 string set(string v){return value = v;} 42 string toString() const => value; 43 44 45 version(Have_util) 46 { 47 import hip.util.sumtype; 48 Sumtype val; 49 pragma(inline, true) T get(T)() 50 { 51 if(val.type == Type.undefined) 52 val = Sumtype.make!T(value); 53 return val.get!T; 54 } 55 pragma(inline, true) T set(T)(T v) => val.set(v); 56 } 57 } 58 59 /** 60 * A simple object which can mean absolutely anything inside a TileLayer. 61 * Usually used for implementing: 62 - Camera Dead Zones 63 - Event Systems 64 - Trigger Areas 65 */ 66 struct TileLayerObject 67 { 68 ushort gid; 69 uint height; 70 ushort id; 71 string name; 72 int rotation; 73 string type; 74 bool visible; 75 uint width; 76 int x; 77 int y; 78 TileProperty[string] properties; 79 } 80 81 /** 82 * The TileAnimationFrame holds what is the ID of the current frame in a TileAnimation and how much duration. 83 */ 84 struct TileAnimationFrame 85 { 86 ushort id; 87 int duration; 88 } 89 90 /** 91 * The Tile is the smallest piece of a TileMap. 92 */ 93 struct Tile 94 { 95 ///ID for backreferencing from TileMap 96 ushort id; 97 ///Which frame is in its animatoin 98 ushort currentFrame; 99 ///The tile texture region itself. 100 IHipTextureRegion region; 101 /** 102 * Properties about the tile. Usually used for implementing gameplay stats such as: 103 - Sounds 104 - Collisions and Collidibles 105 - Visual Effects 106 */ 107 TileProperty[string] properties; 108 ///Frames for playing the tile animation 109 TileAnimationFrame[] animation; 110 alias properties this; 111 } 112 113 /** 114 * Tile Layer is a map of tiles consisting in a unique "texture" of tiles. 115 */ 116 final class HipTileLayer 117 { 118 ///Layer name on the tilemap editor 119 string name; 120 ///Data 121 ushort[] tiles; 122 bool visible = true; 123 int x, y, columns, rows, width, height; 124 uint tileWidth, tileHeight; 125 ushort id; 126 string type; 127 string drawOrder; 128 TileProperty[string] properties; 129 float opacity = 1.0; 130 131 this(IHipTilemap map) 132 { 133 tileWidth = map.tileWidth; 134 tileHeight = map.tileHeight; 135 } 136 137 /** 138 * 139 */ 140 this(string name, uint columns, uint rows, ushort id, IHipTilemap map) 141 { 142 this(map); 143 this.name = name; 144 this.id = id; 145 this.columns = columns; 146 this.rows = rows; 147 tiles = new ushort[columns*rows]; 148 width = columns*tileWidth; 149 height = rows*tileHeight; 150 } 151 152 bool isInLayerBoundaries(int x, int y, int w, int h) const @nogc 153 { 154 int x2 = x+w; 155 int y2 = y+h; 156 157 bool notInBoundariesX = x2 < this.x || x > this.width + this.x; 158 if(notInBoundariesX) 159 return false; 160 bool notInBoundariesY = y2 < this.y || y > this.height + this.y; 161 162 return !notInBoundariesY; 163 } 164 165 ///Expects I and J in column/row 166 final ushort getTile(uint i, uint j) @nogc @safe 167 { 168 return tiles[j*columns+i]; 169 } 170 final ushort checkedGetTile(uint i, uint j) @nogc @trusted 171 { 172 int target = j*columns+i; 173 if(i >= columns || j >= rows || target < 0 || target >= tiles.length) 174 return 0; 175 return tiles.ptr[target]; 176 } 177 178 ///Gets tile from relative X and Y. Does not take into account the layer x, y 179 final ushort getTileXY(uint x, uint y) @nogc @safe 180 { 181 return getTile(cast(uint)(x / tileWidth), cast(uint)(y / tileHeight)); 182 } 183 184 ///Gets tile from absolute X and Y. Takes into account the layer x, y 185 final ushort checkedGetTileXY(int x, int y) @nogc @trusted 186 { 187 if(x < this.x || y < this.y || x > this.x+this.width || y > this.y+this.height) 188 return 0; 189 y-= this.y; 190 x-= this.x; 191 return checkedGetTile(x / tileWidth, y / tileHeight); 192 } 193 194 } 195 196 /** 197 * Tileset is a data set containing tiles. It has information about the underlying texture used for a tile. 198 */ 199 interface IHipTileset 200 { 201 uint columns() const; 202 203 ///Means where the tileset id starts 204 uint firstGid() const; 205 206 207 ///"image" in tiled 208 209 string texturePath() const; 210 ///"imageheight" in tiled 211 uint textureHeight() const; 212 ///"imagewidth" in tiled 213 uint textureWidth() const; 214 215 IHipTexture texture(); 216 int margin() const; 217 string name() const; 218 219 ///Only available when loaded via .tsx 220 string path() const; 221 int spacing() const; 222 uint tileHeight() const; 223 uint tileWidth() const; 224 225 ///Usually only accessed when looking for a specific property 226 Tile[] tiles(); 227 228 final uint tileCount()const {return cast(uint)(cast(IHipTileset)this).tiles.length;} 229 final IHipTextureRegion getTextureRegion(ushort id) 230 { 231 return tiles[id - firstGid].region; 232 } 233 final Tile* getTile(ushort id){return &tiles[id - firstGid];} 234 } 235 236 237 /** 238 * Tilemap is a set of tile layers. It contains information on the maximum map size, holds all the tilesets needed for 239 * actually drawing the layers. 240 */ 241 interface IHipTilemap 242 { 243 @nogc ref int x(); 244 @nogc ref int y(); 245 @nogc ref HipColor color(); 246 @nogc ref float scaleX(); 247 @nogc ref float scaleY(); 248 249 ///Returns scaleX as the one to be modified. 250 @nogc float scale(); 251 ///Modifies both scaleX and scaleY at the same time. 252 @nogc float scale(float v); 253 ref float rotation(); 254 255 256 string path() const; 257 uint width() const @nogc; 258 uint height() const @nogc; 259 bool isInfinite() const @nogc; 260 ref HipTileLayer[string] layers(); 261 string orientation() const @nogc; 262 string renderorder() const @nogc; 263 string tiled_version() const @nogc; 264 265 uint tileHeight() const @nogc; 266 uint tileWidth() const @nogc; 267 268 final uint tileWidthScaled() @nogc {return cast(uint)(scaleX * tileWidth);} 269 final uint tileHeightScaled() @nogc {return cast(uint)(scaleY * tileHeight);} 270 271 void setTileSize(uint tileWidth, uint tileHeight); 272 ///Use it when programatically creating your tilemap 273 void addTileset(IHipTileset tileset); 274 ///Use it when programatically creating your tilemap 275 final HipTileLayer addNewLayer(string layerName, uint columns, uint rows) 276 { 277 return layers[layerName] = new HipTileLayer(layerName, columns, rows, cast(ushort)layers.length, this); 278 } 279 280 281 IHipTileset getTilesetForID(ushort id); 282 final IHipTextureRegion getTextureRegionForID(ushort id){return getTilesetForID(id).getTextureRegion(id);} 283 final Tile* getTileForID(ushort id){return getTilesetForID(id).getTile(id);} 284 285 286 alias layers this; 287 }